#pragma once
#include <map>

#include "CategoryDef.h"
#include "PointsOfImageUI.h"

class PointsUI;

struct PointOfGrad {
	PointOfGrad( PointsDatabase::iterator _imIter, PointsDatabase::PointsInImage::iterator piter, 
		ImageGroupData &imdata, CvSize winSize )
	{
		imIter = _imIter;
		iter = piter;
		
		imRoi = 
			cvRect( 
				piter->loc.x - winSize.width/2, 
				piter->loc.y - winSize.height/2, 
				winSize.width, 
				winSize.height );
		
		cvSetImageROI( imdata.image, imRoi );
		smImage = cvCreateImage( cvSize( imdata.image->roi->width, imdata.image->roi->height), IPL_DEPTH_8U, 3);

		cvCopy( imdata.image, smImage );
		cvResetImageROI( imdata.image );

		selected = false;		
	}
	~PointOfGrad() {
		cvReleaseImage( &smImage );
	}
	PointsDatabase::iterator imIter;
	PointsDatabase::PointsInImage::iterator iter;
	IplImage* smImage;
	CvRect imRoi;

	bool selected;
};

class PointsOfGradUI
{
protected:
	struct CategorizedPts;
	struct CategoryUIInfo;
	typedef map<string,CategorizedPts*> CatMap;
	typedef list<CategoryUIInfo> CatUIList;
public:
	struct MouseCallbackParams;
	PointsOfGradUI( ImageDepthList *imlist, PointsDatabase *pts, float tolDeg );
	~PointsOfGradUI();

	void run();

	void drawCategorizedPtsOfGrad( IplImage* dispIm, CatMap &catPts, MouseCallbackParams &p );
	static void mouseCallback( int evt, int x, int y, int flags, void* param);

protected:
	
	void drawCheckBoxes( IplImage* dispIm, MouseCallbackParams &p );

	void refreshPoints( MouseCallbackParams& p );
	void deleteSelectedPtsOfGrad( list< PointOfGrad* > &ptsOfGrad, ImageDepthList &imlist, CvSize winLayout, CvSize winSize, IplImage* dispIm, int lineOffset );
	void categorizePtsOfGrad( CatMap &CatMap, list< PointOfGrad* > &ptsOfGrad, const MouseCallbackParams &p );

protected: 
	PointsOfImageUI* m_imUI;
	PointsOfImageUI::MouseCallbackParams m_imUI_params;
	PointsOfImageUI::DisplayTemp m_imUI_temp;

	ImageDepthList* m_imlist;
	PointsDatabase* m_pts;
	float m_desiredGrad;

	size_t m_numGrads;
	list< PointOfGrad* >* m_aPtsGrad;

	float m_tol;
	float m_tolDeg;
	float m_localPxRadius;
	PointsUI * m_ptsUI;
	CvFont m_font;
	int m_checkBoxHeight;

public:
	struct MouseCallbackParams {
		MouseCallbackParams( PointsOfGradUI* _pogui, CvSize _winSizePnl, CvSize _panelSizePx, CatMap* _cats ) : pogui( _pogui ), catPts(_cats)
		{
			panelSizePx = cvSize(50,50);
			winSizePnl = _winSizePnl;
			panelSizePx = _panelSizePx;
			lineOffset = 0;
			gradIndex = 0;
			modPtIter = 0;
			catUpdated = true;
			redrawDisplayImage = false;
			lastClicked = NULL;
			bRedrawLastClicked = false;
		}
		CvSize winSizePx() const {
			return cvSize( panelSizePx.width*winSizePnl.width, panelSizePx.height*winSizePnl.height );
		}
		PointsOfGradUI* const pogui;
		CvSize winSizePnl; //!< window size in "panels"
		CvSize panelSizePx; //!< panel size in pixels

		list< PointOfGrad* >::iterator * modPtIter;

		int lineOffset;
		int gradIndex;
		CatMap* const catPts;
		CatUIList cats;
		bool catUpdated; // category enabled or disabled
		bool redrawDisplayImage;
		bool bRedrawLastClicked;
		PointOfGrad* lastClicked;
	};
	struct CategorizedPts {
		CategorizedPts( string _catname ) : catname(_catname) {
		}
		
		list< PointOfGrad* > pts;
		const string catname;
		int lineOffset;
		set<string> imNames;
	};
	struct CategoryUIInfo {
		CategoryUIInfo( CategoryDef* _def )
		{
			def = _def;
			enabled = false;
		}
		void deleteThis()
		{
			if( def ) delete def;
			def = 0;
		}
		CvRect chkbox;
		bool enabled;
		CategoryDef* def;
	};

};